package com.smart.mac.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.smart.mac.common.CommonConstants;
import com.smart.mac.common.R;
import com.smart.mac.config.FlowServiceConfig;
import com.smart.mac.mapper.FlowProcDefMapper;
import com.smart.mac.model.vo.FlowProcDefVO;
import com.smart.mac.model.vo.UserDemoVO;
import com.smart.mac.service.FlowDefinitionService;
import com.smart.mac.utls.LocalSessionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.InputStream;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;

/**
 * FlowDefinitionServiceImpl
 *
 * @Author mac
 */
@Slf4j
@Service
public class FlowDefinitionServiceImpl extends FlowServiceConfig implements FlowDefinitionService {

    @Autowired
    private FlowProcDefMapper flowProcDefMapper;

    @Override
    public void importFile(String name, String category, InputStream in) {
        //租户ID，TODO: 正式开发从SecurityContext获取就行
        UserDemoVO userDemo = (UserDemoVO) LocalSessionUtils.get();
        String tenantId = userDemo.getCompanyId();
        //设置
       /* ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
        processEngineConfiguration.setDefaultTenantValue(tenantId);*/
        //上传流程文件，并部署流程图
        Deployment deploy = repositoryService.createDeployment().addInputStream(name + CommonConstants.BPMN_FILE_SUFFIX, in)
                .name(name).category(StringUtils.isEmpty(category)?null:category).tenantId(tenantId).deploy();
        if (StringUtils.isNotEmpty(category)){
            //设置流程定义的分类
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();
            repositoryService.setProcessDefinitionCategory(processDefinition.getId(),category);
        }
    }

    @Override
    public InputStream readImage(String deployId) {
        //获取租户流程定义
        ProcessDefinition processDefinition = getTenantProcessDefinition(null, deployId);
        //获取图片流
        DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        ProcessEngineConfiguration processEngineConfiguration = processEngine.getProcessEngineConfiguration();
        return processDiagramGenerator.generateDiagram(bpmnModel,
                "png",
                Collections.emptyList(),
                Collections.emptyList(),
                processEngineConfiguration.getActivityFontName(),
                processEngineConfiguration.getLabelFontName(),
                processEngineConfiguration.getAnnotationFontName(),
                null,
                1.0,
                false);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R startProcessInstanceById(String procDefId, Map<String, Object> variables) {
        //租户ID，TODO: 正式开发从SecurityContext获取就行
        UserDemoVO userDemo = (UserDemoVO)LocalSessionUtils.get();
        String tenantId = userDemo.getCompanyId();
        String userId = userDemo.getId();
        //获取最新版本流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId).processDefinitionTenantId(tenantId)
                .latestVersion().singleResult();
        Assert.isTrue(Objects.nonNull(processDefinition) && !processDefinition.isSuspended(),"流程定义为空或挂起不能开启");
        //设置发起人到流程中
        identityService.setAuthenticatedUserId(userId);
        runtimeService.startProcessInstanceByKeyAndTenantId(processDefinition.getKey(),variables,tenantId);
        return R.ok("流程开启成功");
    }

    @Override
    public R startProcessInstanceByKey(String procDefKey, String businessKey, Map<String, Object> variables) {
        //租户ID，TODO: 正式开发从SecurityContext获取就行
        UserDemoVO userDemo = (UserDemoVO)LocalSessionUtils.get();
        String tenantId = userDemo.getCompanyId();
        String userId = userDemo.getId();
        //获取最新版本流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).processDefinitionTenantId(tenantId)
                .latestVersion().singleResult();
        Assert.isTrue(Objects.nonNull(processDefinition) && !processDefinition.isSuspended(),"流程定义为空或挂起不能开启");
        //设置发起人到流程中
        identityService.setAuthenticatedUserId(userId);
        runtimeService.startProcessInstanceByKeyAndTenantId(processDefinition.getKey(),businessKey,variables,tenantId);
        return R.ok("流程开启成功");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateState(Integer state, String deployId) {
        //获取租户流程定义
        ProcessDefinition processDefinition = getTenantProcessDefinition(null, deployId);
        if (state == 1){//激活
            repositoryService.activateProcessDefinitionById(processDefinition.getId(),true,null);
        }else if (state == 2){//挂起
            repositoryService.suspendProcessDefinitionById(processDefinition.getId(),true,null);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(String deployId) {
        //获取租户流程定义
        getTenantProcessDefinition(null, deployId);
        // true 允许级联删除 ,不设置会导致数据库外键关联异常
        repositoryService.deleteDeployment(deployId, true);
    }

    @Override
    public Page<FlowProcDefVO> page(String name, Integer pageNum, Integer pageSize) {
        Page<FlowProcDefVO> voPage = new Page<>(pageNum,pageSize);
        //租户ID，TODO: 正式开发从SecurityContext获取就行
        UserDemoVO userDemo = (UserDemoVO)LocalSessionUtils.get();
        String tenantId = userDemo.getCompanyId();
        voPage = flowProcDefMapper.page(voPage,name,tenantId);
        return voPage;
    }
}
